﻿Imports System.Windows.Interop
Imports System.Runtime.InteropServices.Automation
Imports System.IO
Imports System.Windows.Media.Imaging

Class WordHelper
    Implements IDisposable

    Private _word As Object
    Private _document As Object

    Public ReadOnly Property Word
        Get
            Try
                Return _word
            Catch ex As Exception
                Return Nothing
            End Try
        End Get
    End Property

    Public Property Document
        Get
            Try
                If _document Is Nothing Then
                    If _word.Documents.Count > 0 Then
                        _document = _word.ActiveDocument
                    Else
                        _document = _word.Documents.Add()
                    End If
                End If

                Return _document

            Catch ex As Exception
                Return Nothing
            End Try
        End Get
        Set(value)
            _document = value
        End Set
    End Property

    ' Use this method to retrieve active Word session
    Public Function GetWord() As Boolean
        Try
            ' If GetObject throws an exception, then Word is 
            ' either not running or is not available.
            _word = AutomationFactory.GetObject("Word.Application")
            Return True
        Catch
            Return False
        End Try
    End Function

    ' Use this method to explicity create a new instance of Word
    Public Function CreateWord() As Boolean
        Try
            ' If CreateObject throws an exception, then Word is not available.
            _word = AutomationFactory.CreateObject("Word.Application")
            Return True
        Catch
            Return False
        End Try
    End Function

    Public Sub OpenDocument(ByVal filePath As String)
        Dim o As Object
        o = Word
        If o IsNot Nothing Then
            If File.Exists(filePath) Then
                o.Documents.Open(filePath)
            Else
                Throw New ArgumentException("The file '" & filePath & "' does not exist.", "FilePath")
            End If
        Else
            Throw New InvalidProgramException("Error: Could not open Word document. Please make sure Word is installed.")
        End If
    End Sub

    Public Sub CreateDocument()
        Dim o As Object
        o = Word
        If o IsNot Nothing Then
            Document = o.Documents.Add()
        End If
    End Sub

    Public Sub CloseDocument()
        If Document IsNot Nothing Then
            Document.Save()
            Document.Close()
            Document = Nothing
        End If
    End Sub

    Public Sub ShowDocument()
        Dim o As Object
        o = Word
        If o IsNot Nothing Then
            o.Visible = True
        End If
    End Sub

    ' Adds a table to the end of the Document
    Public Function AddTable(RowCount As Int32, ColumnCount As Int32) As Object
        Dim o As Object
        o = Nothing

        If Document IsNot Nothing Then
            Try
                Dim range As Object = Document.Bookmarks.Item("\endofdoc").Range
                Document.Tables.Add(range, RowCount, ColumnCount)
            Catch Ex As Exception
                ' Method call works, but throws a COM exception on returning back to Silverlight
            End Try

            If Document.Tables.Count > 0 Then
                ' use last table
                o = Document.Tables(1)
                o.ApplyStyleHeadingRows = True
                o.Style = "Medium Shading 1 - Accent 1"
                o.ApplyStyleFirstColumn = False
            End If
        End If
        AddTable = o
    End Function

    ' Adds a table to the specified range of the Document
    Public Function AddTable(RowCount As Int32, ColumnCount As Int32, LocationRange As Object) As Object
        Dim o As Object
        o = Nothing

        If Document IsNot Nothing Then
            Try
                Document.Tables.Add(LocationRange, RowCount, ColumnCount)
            Catch Ex As Exception
                ' Method call works, but throws a COM exception on returning back to Silverlight
            End Try

            If LocationRange.Tables.Count > 0 Then
                ' use last table
                o = LocationRange.Tables(1)
                o.ApplyStyleHeadingRows = True
                o.Style = "Medium Shading 1 - Accent 1"
                o.ApplyStyleFirstColumn = False
            End If
        End If
        AddTable = o
    End Function

    Public Sub SetTableCell(Table As Object, Row As Int32, Column As Int32, Value As String)
        Table.Cell(Row, Column).Range.Text = Value
    End Sub

    Public Sub SetTableCell(Table As Object, Row As Int32, Column As Int32, Value As Byte())
        Dim range As Object = Table.Cell(Row, Column).Range
        If range.InlineShapes.Count > 0 Then
            range.InlineShapes(1).Delete()
        End If
        Dim imageFilePath As String = CreateFile(Value)
        Document.InlineShapes.AddPicture(imageFilePath, False, True, range)
        File.Delete(imageFilePath)
    End Sub

    Public Function ContentControlCount() As Int32
        Return Document.ContentControls.Count
    End Function

    Public Sub SetContentControl(ContentControlTitle As String, Value As String)
        For Each cc In Document.ContentControls
            If cc.Title = ContentControlTitle Then
                cc.Range.Text = Value
                ' Populate every content control having the title = ContentControlTitle
                'Exit For
            End If
        Next
    End Sub

    Public Sub SetContentControl(ContentControlTitle As String, Value As Byte())
        For Each cc In Document.ContentControls
            If cc.Title = ContentControlTitle And cc.Type = 2 Then
                If cc.Range.InlineShapes.Count > 0 Then
                    cc.Range.InlineShapes(1).Delete()
                End If

                Dim imageFilePath As String = CreateFile(Value)
                Dim range As Object = cc.Range
                Document.InlineShapes.AddPicture(imageFilePath, False, True, range)
                File.Delete(imageFilePath)
                ' Populate every content control having the title = ContentControlTitle
                'Exit For
            End If
        Next
    End Sub

    Public Function CreateFile(FileContent As Byte()) As String
        Dim filePath = Path.GetTempFileName()
        Dim fileStream As New FileStream(filePath, FileMode.OpenOrCreate)
        Dim bw As New BinaryWriter(fileStream)
        bw.Write(FileContent)
        bw.Close()
        fileStream.Close()
        CreateFile = filePath
    End Function


    Public ReadOnly Property GetContentControls() As IEnumerable(Of ContentControl)
        Get
            Dim controls As New List(Of ContentControl)

            For Each cc In Document.ContentControls
                controls.Add(New ContentControl(cc.Title))
            Next
            Return controls
        End Get
    End Property

#Region "IDisposable Support"
    Private disposedValue As Boolean ' To detect redundant calls

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then

            Word.DisplayAlerts = False
            Word.Quit()

            _word = Nothing
        End If
        Me.disposedValue = True
    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region
End Class


Friend Class ContentControl
    Public Sub New(ByVal Title As String)
        Me.Title = Title
    End Sub
    Public Property Title As String
End Class